from rest_framework import serializers
from . import models
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
from django.core.cache import cache
from django.conf import settings


# 序列化类用来，反序列化，验证前端传入的字段是否合法
class LoginSerializer(serializers.ModelSerializer):
    # 坑
    '''
    username:由于映射了User表的Username，自己有规则，unique=True
    username字段自己的校验，会走unique，会去数据库查是否有这个用户，如果有，直接抛异常
    重写这个字段，不设置规则
    '''
    username = serializers.CharField(max_length=16, min_length=3)

    class Meta:
        model = models.User
        fields = ['username', 'password']

    # 用户校验和签发token
    def validate(self, attrs):
        '''
        1 根据用户名（手机号，邮箱）获取用户
        2 如果用户存在，签发token
        3 把token放到序列化类的对象中
        '''
        # request=self.context.get('request')
        # print(request.GET)
        # request=self.context.get('request')
        user = self._get_user(attrs)
        token = self._get_token(user)
        # 上下文，是个字典
        self.context['token'] = token
        self.context['username'] = user.username

        return attrs

    def _get_user(self, attrs):  # 不是私有，但尽量只给内部用
        username = attrs.get('username')
        password = attrs.get('password')
        # 多种登录方式,正则匹配，如果是手机号根据手机号查。。。
        # ^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = models.User.objects.filter(mobile=username).first()
        # elif re.match(r'[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$',username):

        elif re.match(r'^.+@.+$', username):
            user = models.User.objects.filter(email=username).first()
        else:
            user = models.User.objects.filter(username=username).first()

        if user and user.check_password(password):
            return user
        else:
            raise ValidationError('用户名或密码错误')

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


class MobileLoginSerializer(serializers.ModelSerializer):
    # 重写它的原因，unique=True
    mobile = serializers.CharField()
    # code 由于不是表的字段，所有必须重写
    code = serializers.CharField()

    class Meta:
        model = models.User
        fields = ['code', 'mobile']

    # 用户校验和签发token
    def validate(self, attrs):
        '''
        1 校验code是否正确：从缓存中根据手机号获取code，比较

        2 根据手机号，拿到当前用户，
        3 根据用户，签发token
        3 把token放到序列化类的对象中
        '''

        user = self._get_user(attrs)
        token = self._get_token(user)
        # 上下文，是个字典
        self.context['token'] = token
        self.context['username'] = user.username

        return attrs

    def _get_user(self, attrs):  # 不是私有，但尽量只给内部用
        code = attrs.get('code')
        mobile = attrs.get('mobile')
        # 校验code
        cache_code = cache.get(settings.CACHE_SMS % mobile)
        if cache_code and code == cache_code:
            user = models.User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise ValidationError({'detail': '用户名或密码错误'})
        else:
            raise ValidationError({'detail': '验证码错误'})

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


class RegisterUserSerializer(serializers.ModelSerializer):
    # code 不是User表的字段，必须重写
    code = serializers.CharField(max_length=4, min_length=4,write_only=True)

    class Meta:
        model = models.User
        fields = ['mobile', 'code', 'password', 'username']
        extra_kwargs = {'mobile': {'write_only': True},
                        'password': {'write_only': True}, 'username': {'read_only': True}}

    # 如果想让密码比较复杂，可以给密码写一个局部钩子，使用正则去匹配
    # 校验字段
    def validate(self, attrs):
        '''
        1 校验code是否正确
        2 把code从attrs中剔除
        3 使用手机号作为用户名，后期可以改
        '''
        code = attrs.get('code')
        mobile = attrs.get('mobile')
        # 校验code
        cache_code = cache.get(settings.CACHE_SMS % mobile)
        if cache_code and code == cache_code:
            # 把code剔除，code不是User表的字段，不能用来保存
            attrs.pop('code')
            # 创造一个username
            attrs['username'] = mobile
        else:
            raise ValidationError({'detail': '验证码错误'})

        return attrs

    # 为什么要重写create? 因为密码是明文的，需要使用create_user创建用户
    def create(self, validated_data):

        user = models.User.objects.create_user(**validated_data)
        return user
